import React, {
  useState,
  useRef,
  useEffect,
  useCallback,
  useImperativeHandle,
  forwardRef,
} from 'react';
import { message, Menu } from 'antd';
import { useDrop } from 'react-dnd';
import styles from './WorkFlowEditor.less';
import WorkFlowGraph from './graph-wrapper/work-flow-graph';
import { EventItemType } from './dict';
import { useClickAway } from 'ahooks';
import CanvaTools from './CanvaTools';

function MainCanvas(props, ref) {
  const { flowGraphData, dispatch } = props;

  const containerRef = useRef(null);
  const canvasRef = useRef(null);
  const flowGraphRef = useRef(null);
  const contextMenuRef = useRef(null);
  const miniMapRef = useRef(null);
  const [showContextMenu, setShowContextMenu] = useState(false);
  const [point, setPoint] = useState({ x: 0, y: 0 });

  useImperativeHandle(ref, () => ({
    // graphJson: () => flowGraphRef.toJSON({ deep: true }),
    graphJson: () => flowGraphRef.current.toJSON(),
    updateGraphProps: (id, propsByPath, value) =>
      flowGraphRef.current.updateGraphProps(id, propsByPath, value),
  }));

  // 渲染画布
  useEffect(() => {
    let sub;
    if (flowGraphData) {
      flowGraphRef.current = new WorkFlowGraph();
      flowGraphRef.current.workflowGraph$.next(flowGraphData);
      flowGraphRef.current.renderGraph(
        containerRef.current,
        canvasRef.current,
        miniMapRef.current,
        dispatch,
      );

      // 右键 context menu 事件
      sub = flowGraphRef.current.contextMenuInfo$.subscribe((event) => {
        if (!event || event.type === 'graph') {
          setShowContextMenu(false);
          return;
        }
        const {
          type,
          data: { x, y, node },
        } = event;
        // node.id, node.data.type
        // console.log('right click: ', node);
        setShowContextMenu(true);
        setPoint(flowGraphRef.current.graphPointToOffsetPoint({ x, y }));
      });
    }
    return () => {
      if (flowGraphRef.current) {
        flowGraphRef.current.dispose();
        flowGraphRef.current = null;
        sub.unsubscribe();
      }
    };
  }, [flowGraphData, dispatch]);

  useClickAway(() => {
    flowGraphRef.current.clearContextMenuInfo();
  }, contextMenuRef);

  // 处理组件拖拽落下事件
  const [, dropRef] = useDrop({
    accept: [EventItemType.WorkTask, EventItemType.VerifyTask],
    drop: (item, monitor) => {
      const currentMouseOffset = monitor.getClientOffset();
      const sourceMouseOffset = monitor.getInitialClientOffset();
      const sourceElementOffset = monitor.getInitialSourceClientOffset();
      const diffX = sourceMouseOffset.x - sourceElementOffset.x;
      const diffY = sourceMouseOffset.y - sourceElementOffset.y;
      const x = currentMouseOffset.x - diffX;
      const y = currentMouseOffset.y - diffY;
      if (flowGraphRef.current.isGraphReady()) {
        flowGraphRef.current.requestAddNode({
          clientX: x,
          clientY: y,
          itemType: item.type,
        });
      } else {
        message.info('数据建立中，请稍后再尝试添加节点');
      }
    },
  });

  const onDel = useCallback(() => {
    if (flowGraphRef.current) {
      flowGraphRef.current.onDeleteSelectedCells();
    }
    setShowContextMenu(false);
  }, []);

  // 画布侧边 toolbar handler
  const onHandleSideToolbar = useCallback(
    // action : 'in' | 'out' | 'fit' | 'real'
    (action) => () => {
      // 确保画布已渲染
      if (flowGraphRef.current) {
        switch (action) {
          case 'in':
            flowGraphRef.current.zoom(0.1);
            break;
          case 'out':
            flowGraphRef.current.zoom(-0.1);
            break;
          case 'fit':
            flowGraphRef.current.zoom('fit');
            break;
          case 'real':
            flowGraphRef.current.zoom('real');
            break;
          default:
        }
      }
    },
    [flowGraphData, dispatch],
  );

  return (
    <div
      ref={(elem) => {
        containerRef.current = elem;
        dropRef(elem);
      }}
      className={styles.dropWapper}
    >
      <div style={{ height: '100%', width: '100%' }} ref={canvasRef} />
      {showContextMenu && (
        <div className={styles.contextMenuWrapper}>
          <div
            ref={contextMenuRef}
            className={styles.graphContextMenu}
            style={{ top: `${point.y}px`, left: `${point.x}px` }}
          >
            <Menu>
              <Menu.Item onClick={onDel}>删除</Menu.Item>
            </Menu>
          </div>
        </div>
      )}

      {/* 缩放相关的 toolbar */}
      <CanvaTools
        onZoomIn={onHandleSideToolbar('in')}
        onZoomOut={onHandleSideToolbar('out')}
        onFitContent={onHandleSideToolbar('fit')}
        onRealContent={onHandleSideToolbar('real')}
      />

      <div ref={miniMapRef} className={styles.miniMap} />
    </div>
  );
}

export default forwardRef(MainCanvas);
